package io.youngledo.usb.storage.impl;

import io.youngledo.usb.storage.*;
import io.youngledo.usb.exception.StorageOperationException;
import io.youngledo.usb.config.TimeoutConfig;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;

import java.io.*;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;

/// 阿里云OSS存储服务适配器，[地域和访问域名](https://help.aliyun.com/zh/oss/regions-and-endpoints?spm=a2c4g.11186623.0.0.27845533LFXiih#concept-zt4-cvy-5db)
///
public class AliyunStorageService extends AbstractObjectStorageService {

    private OSS client;

    @Override
    public void connect(StorageConfig config) {
        if (config.type() != StorageType.ALIYUN_OSS) {
            throw new IllegalArgumentException("Invalid storage type for Aliyun OSS service: " + config.type());
        }

        this.config = config;

        // 创建客户端配置，使用统一的超时配置
        com.aliyun.oss.ClientBuilderConfiguration clientConfig = new com.aliyun.oss.ClientBuilderConfiguration();
        clientConfig.setConnectionTimeout(TimeoutConfig.CONNECTION_TIMEOUT_MS);
        clientConfig.setSocketTimeout(TimeoutConfig.SOCKET_TIMEOUT_MS);
        clientConfig.setMaxConnections(100);      // 最大连接数

        this.client = new OSSClientBuilder().build(
                config.endpoint(),
                config.accessKey(),
                config.secretKey(),
                clientConfig
        );

        // 测试连接 - 让运行时异常自然传播
        client.listBuckets();
        this.connected = true;
    }

    @Override
    protected void performDisconnect() {
        if (client != null) {
            client.shutdown();
        }
        this.client = null;
    }

    @Override
    public List<StorageBucket> listBuckets() {
        checkConnection();

        return client.listBuckets()
                .parallelStream()
                .map(bucket -> StorageBucket.of(
                        bucket.getName(),
                        bucket.getCreationDate() != null ?
                                bucket.getCreationDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
                                : null
                )).toList();
    }

    @Override
    public void createBucket(String bucketName) {
        checkConnection();
        client.createBucket(bucketName);
    }

    @Override
    public void deleteBucket(String bucketName) {
        checkConnection();
        client.deleteBucket(bucketName);
    }

    @Override
    public List<StorageObject> listObjects(String bucketName, String prefix, boolean recursive) {
        checkConnection();

        ListObjectsRequest request = new ListObjectsRequest(bucketName);
        if (prefix != null) {
            request.setPrefix(prefix);
        }
        if (!recursive) {
            request.setDelimiter("/");
        }

        ObjectListing listing = client.listObjects(request);
        List<StorageObject> objects = new ArrayList<>();

        // 处理文件
        objects.addAll(ObjectStorageHelper.processObjects(
                listing.getObjectSummaries(),
                prefix,
                OSSObjectSummary::getKey,
                (summary, key, displayName) -> new StorageObject(
                        key,
                        displayName,
                        summary.getSize(),
                        summary.getLastModified() != null ?
                                summary.getLastModified().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
                                : null,
                        false,
                        summary.getETag()
                )
        ));

        // 处理目录（如果不是递归模式）
        if (!recursive) {
            objects.addAll(ObjectStorageHelper.processCommonPrefixes(
                    listing.getCommonPrefixes(),
                    prefix,
                    false  // 不移除末尾的斜杠
            ));
        }

        return objects;
    }

    @Override
    public void uploadFile(String bucketName, String objectKey, File file) {
        checkConnection();
        client.putObject(bucketName, objectKey, file);
    }

    @Override
    public void uploadFile(String bucketName, String objectKey, InputStream inputStream, long contentLength) {
        checkConnection();
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(contentLength);
        client.putObject(bucketName, objectKey, inputStream, metadata);
    }

    @Override
    public InputStream downloadFile(String bucketName, String objectKey) {
        checkConnection();
        OSSObject object = client.getObject(bucketName, objectKey);
        return object.getObjectContent();
    }

    @Override
    public void downloadFile(String bucketName, String objectKey, File localFile) {
        checkConnection();
        // 这里需要try-catch，因为FileOutputStream和I/O操作会抛出受检异常(IOException)
        try (InputStream inputStream = downloadFile(bucketName, objectKey);
             FileOutputStream outputStream = new FileOutputStream(localFile)) {
            inputStream.transferTo(outputStream);
        } catch (IOException e) {
            throw StorageOperationException.objectNotFound(objectKey);
        }
    }

    @Override
    public void deleteObject(String bucketName, String objectKey) {
        checkConnection();
        client.deleteObject(bucketName, objectKey);
    }

    @Override
    public void deleteObjects(String bucketName, List<String> objectKeys) {
        checkConnection();
        DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName);
        request.setKeys(objectKeys);
        client.deleteObjects(request);
    }

    @Override
    public StorageObject getObjectInfo(String bucketName, String objectKey) {
        checkConnection();
        ObjectMetadata metadata = client.getObjectMetadata(bucketName, objectKey);

        return new StorageObject(
                objectKey,
                objectKey.substring(objectKey.lastIndexOf('/') + 1),
                metadata.getContentLength(),
                metadata.getLastModified() != null ?
                        metadata.getLastModified().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
                        : null,
                false,
                metadata.getETag()
        );
    }

    @Override
    public StorageType getStorageType() {
        return StorageType.ALIYUN_OSS;
    }


}